import time
import json
import urllib2
import logging
import traceback
import Card

#logging.basicConfig(level=logging.INFO,filename="futclient.log",format="%(asctime)s - %(levelname)s - %(message)s")


class UrlRequestor(object):
    """Class to handle opening and reading of urls."""
    def __init__(self, url):
        self.url = url
        self.request = urllib2.Request(str(url))
        self.status = False

    def addHeader(self, header):
        """Add header to url request. header should be dict type."""
        self.header = header
        if isinstance(header, dict):
            for headerName, headerContent in self.header.iteritems():
                self.request.add_header(headerName, headerContent)
        else:
            logging.error("UrlRequestor.addHeader - Error adding header: data type required is 'dict', but type given was %s" % type(self.header))

    def addData(self, data):
        """Add data to url request. Data should be string."""
        self.data = data
        if isinstance(self.data, str):
            self.request.add_data(self.data)
        else:
            logging.error("UrlRequestor.addData - Error adding data: data type required is 'str', but type given was %s" % type(self.data))

    def open(self):
        """Open the url."""
        try:
            self.content = urllib2.urlopen(self.request)
        except urllib2.HTTPError, e:
            logging.error('HTTPError = ' + str(e.code))
        except urllib2.URLError, e:
            logging.error('URLError  = ' + str(e.reason))
        except Exception:
            logging.error('Generic exception: ' + traceback.format_exc())
        else:
            # Everything fine
            self.status = True

    def getHeader(self, headerName):
        # Get specific header
        try:
            return self.content.info().getheader(headerName)
        except Exception, e:
            logging.error("Error getting header '%s' from %s" % (headerName, self.url))
            self.status = False

    def getReturnData(self):
        returnData = self.content.read()
        try:
            return dict(json.loads(returnData))
        except Exception, e:
            if len(returnData) > 0:
                return returnData
            else:
                logging.error("Error getting data from %s" % self.url)
                self.status = False


class FifaClient(object):
    """Class to interact with the web app."""
    def __init__(self, username, password, securityHash, maxTradePile=30):
        self.username = username
        self.password = password
        self.securityHash = securityHash
        self.status = False
        self.maxTradePile = maxTradePile
        self.doLogin()

    def doLogin(self):
        ''' Login to ultimate team web app.
        Returnes true if login is ok
        '''
        self.status = False
        # Get cookie information
        requestor = UrlRequestor("https://www.ea.com/intl/football/services/authenticate/login")
        requestor.addHeader({'Content-Type': 'application/x-www-form-urlencoded'})
        requestor.addHeader({'Referer': 'http://www.ea.com/intl/football/login?redirectUrl=http://www.ea.com/intl/football/fifa-ultimate-team'})
        requestor.addData("email="+self.username+"&password="+self.password+"&stay-signed=ON")
        requestor.open()

        if not requestor.status:
            logging.error("Error trying to login to web app - could not retrieve NUC and cookie information (err1)")
            return
        returnData = requestor.getReturnData()
        if not requestor.status:
            logging.error("Error trying to login to web app - could not retrieve NUC and cookie information (err2)")
            return
        try:
            self.NUC = returnData.split("<nucleusId>")[1].split("</nucleusId>")[0]
            self.gamertag = returnData.split("<gamertag>")[1].split("</gamertag>")[0]
            self.EASW_KEY = requestor.getHeader('Set-Cookie')  # gets key from cookies
            self.EASF_SESS = self.EASW_KEY.split('easf_sess_com=')[1]
            self.EASF_SESS = self.EASF_SESS.split(';')[0]
            self.EASF_SESS = 'easf_sess_com=' + self.EASF_SESS
            self.EASW_KEY = self.EASW_KEY.split(';')[0]
        except IndexError, e:
            logging.error('Error getting data from https://www.ea.com/intl/football/services/authenticate/login: %s' % e)
            return
        except Exception:
            logging.error('Generic exception: ' + traceback.format_exc())
            return

        # Get correct platform
        requestor = UrlRequestor("http://www.ea.com/p/fut/a/card/l/en/s/p/ut/shards?timestamp="+str(time.time()))
        requestor.addHeader({'Content-Type': 'application/json'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";"})
        requestor.open()
        if not requestor.status:
            logging.error("Error trying to login to web app - could not retrieve correct platform (err1)")
            return
        returnData = requestor.getReturnData()
        if not requestor.status or not isinstance(returnData, dict):
            logging.error("Error trying to login to web app - could not retrieve correct platform (err2)")
            return
        self.card1 = returnData['shardInfo'][1]['customdata1'][0]
        self.card2 = returnData['shardInfo'][1]['customdata1'][1]

        # Using correct platform to get the authdata
        requestor = UrlRequestor("http://www.ea.com/p/fut/a/"+str(self.card1)+"/l/en/s/p/ut/game/fifa13/user/accountinfo?timestamp="+str(time.time()))
        requestor.addHeader({'Content-Type': 'application/json'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";"})
        requestor.open()
        if not requestor.status:
            logging.error("Error trying to login to web app - could not retrieve authdata (err1)")
            return
        returnData = requestor.getReturnData()
        if not requestor.status or not isinstance(returnData, dict):
            logging.error("Error trying to login to web app - could not retrieve authdata (err2)")
            return
        self.nucleusId = str(returnData['userAccountInfo']['personas'][0]['personaId'])
        self.authData = {'priorityLevel': 4, 'locale': 'en-GB', 'nuc': self.NUC, 'nucleusPersonaId': self.nucleusId, 'sku': '393A0001', 'clientVersion': 3, 'isReadOnly': False, 'nucleusPersonaDisplayName': self.gamertag, 'identification': {'EASW-Token': ''}, 'method': 'idm', 'nucleusPersonaPlatform': self.card2.strip('card-')}
        self.authData = json.dumps(self.authData, separators=(',', ':'))

        # Get X-UT-SID
        requestor = UrlRequestor("http://www.ea.com/p/fut/a/"+str(self.card1)+"/l/en_GB/s/p/ut/auth")
        requestor.addHeader({'Content-Type': 'application/json'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";"})
        requestor.addData(self.authData)
        requestor.open()
        if not requestor.status:
            logging.error("Error trying to login to web app - could not retrieve X-UT-SID")
            return
        self.XUT_SID = requestor.getHeader('X-UT-SID')

        # Submit security question (hash) and get FUTPHISHING Key
        requestor = UrlRequestor("http://www.ea.com/p/fut/a/"+str(self.card1)+"/l/en_GB/s/p/ut/game/fifa13/phishing/validate")
        requestor.addHeader({'Content-Type': 'application/x-www-form-urlencoded'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";"})
        requestor.addHeader({'X-UT-SID': self.XUT_SID})
        requestor.addData('answer=' + self.securityHash)
        requestor.open()
        if not requestor.status:
            logging.error("Error trying to login to web app - could not retrieve FUTPHISHING Key")
            return
        self.FUTPHISHING = requestor.getHeader('Set-Cookie').split(';')[0]

        # Login done
        self.status = True

    def searchAuctions(self, start="0", count="16", level="", formation="", position="", nationality="", league="", team="", minBid="", maxBid="", minBIN="", maxBIN="", cardType="development", category=""):
        cardList = list()
        searchstring = "https://utas.s2.fut.ea.com/ut/game/fifa13/auctionhouse"
        searchstring += "?type=" + str(cardType)
        searchstring += "&start=" + str(start)
        searchstring += "&num=" + str(count)

        if formation != "" and formation != "any":
            searchstring += "&form=" + formation
        if position != "" and position != "any":
            if position == "defense" or position == "midfield" or position == "attacker":
                searchstring += "&zone=" + position
            else:
                searchstring += "&pos=" + position
        if nationality:
            searchstring += "&nat=" + str(nationality)
        if league:
            searchstring += "&leag=" + str(league)
        if team:
            searchstring += "&team=" + str(team)
        if minBIN:
            searchstring += "&minb=" + str(minBIN)
        if maxBIN:
            searchstring += "&maxb=" + str(maxBIN)
        if minBid:
            searchstring += "&micr=" + str(minBid)
        if maxBid:
            searchstring += "&macr=" + str(maxBid)
        if category:
            searchstring += "&cat=" + str(category)
        if level != "" and level != "any":
            searchstring += "&lev=" + level

        requestor = UrlRequestor(searchstring)
        requestor.addHeader({'Content-Type': 'application/json'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";" + self.EASF_SESS + "; " + self.FUTPHISHING + "; "})
        requestor.addHeader({'X-UT-SID': self.XUT_SID})
        requestor.addHeader({'x-http-method-override': 'GET'})
        requestor.open()
        if not requestor.status:
            logging.error("Error while trying to access the auctionhouse")
            return False
        auctions = requestor.getReturnData().get('auctionInfo')
        if auctions == [] or not isinstance(auctions, list):
            return False
        else:
            for card in auctions:
                cardList.append(Card.Card(card, self))
            return cardList

    def getTradePileInfo(self):
        ''' Returnes a list of  all the cards in the trade pile '''
        cardList = list()
        requestor = UrlRequestor("https://utas.s2.fut.ea.com/ut/game/fifa13/tradepile")
        requestor.addHeader({'Content-Type': 'application/json'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";" + self.EASF_SESS + "; " + self.FUTPHISHING + "; "})
        requestor.addHeader({'X-UT-SID': self.XUT_SID})
        requestor.addHeader({'x-http-method-override': 'GET'})
        requestor.open()
        if not requestor.status:
            logging.error("Error while trying to retrieve trade pile")
            return cardList

        returnData = requestor.getReturnData().get('auctionInfo')
        if requestor.status and isinstance(returnData, list):
            for card in returnData:
                cardList.append(Card.Card(card, self))
        return cardList

    def getTradePileLength(self):
        # Number of item in tradepile
        return len(self.getTradePileInfo())

    def postTrade(self, itemID, startBid, buyNowPrice, duration):
        ''' Post trade. Duration in seconds '''
        content = {"duration": str(duration), "itemData": {"id": str(itemID)}, "buyNowPrice": str(buyNowPrice), "startingBid": str(startBid)}
        content = json.dumps(content, separators=(',', ':'))
        requestor = UrlRequestor("https://utas.s2.fut.ea.com/ut/game/fifa13/auctionhouse")
        requestor.addHeader({'Content-Type': 'application/json'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";" + self.EASF_SESS + "; " + self.FUTPHISHING + "; "})
        requestor.addHeader({'X-UT-SID': self.XUT_SID})
        requestor.addHeader({'x-http-method-override': 'POST'})
        requestor.addData(content)
        requestor.open()
        if not requestor.status:
            logging.error("Error while trying to post trade")
            return False
        returnData = requestor.getReturnData()
        if not requestor.status:
            return False
        if returnData.get('string') == "Bad Request":
            return False
        return True

    def buyItem(self, trade, value):
        """Buy item."""
        content = json.dumps({"bid": value}, separators=(',', ':'))
        requestor = UrlRequestor("https://utas.s2.fut.ea.com/ut/game/fifa13/trade/"+str(trade)+"/bid")
        requestor.addHeader({'Content-Type': 'application/json'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";" + self.EASF_SESS + "; " + self.FUTPHISHING + "; "})
        requestor.addHeader({'X-UT-SID': self.XUT_SID})
        requestor.addHeader({'x-http-method-override': 'PUT'})
        requestor.addHeader({'X-UT-Embed-Error': True})
        requestor.addData(content)
        requestor.open()
        if not requestor.status:
            logging.error("Error while trying to buy item")
            return False
        if requestor.getReturnData().get('string') == 'Permission Denied':
            return False
        else:
            return True

    def moveCard(self, itemID):
        """Move card to tradepile."""
        content = json.dumps({"itemData": [{"id": itemID, "pile": "trade"}]}, separators=(',', ':'))
        requestor = UrlRequestor("https://utas.s2.fut.ea.com/ut/game/fifa13/item")
        requestor.addHeader({'Content-Type': 'application/json'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";" + self.EASF_SESS + "; " + self.FUTPHISHING + "; "})
        requestor.addHeader({'X-UT-SID': self.XUT_SID})
        requestor.addHeader({'x-http-method-override': 'PUT'})
        requestor.addData(content)
        requestor.open()
        if not requestor.status:
            logging.error("Error while trying to move item")
            return False
        if requestor.getReturnData().get('itemData') != "":
            return True
        return False

    def relistCards(self):
        """Relist all non-active card. This also removes sold cards from tradepile."""
        logging.info("Relisting/removing cards")
        tradePile = self.getTradePileInfo()
        for card in tradePile:
            if card.tradeState != "active":
                if card.itemType == "contract":
                    card.lastSalePrice = 250
                    card.price = 300
                    # Only relisting contracts at the moment
                    if self.postTrade(card.itemID, str(card.lastSalePrice), str(card.price), "3600"):
                        if card.tradeState == "expired":
                            logging.info("Relisting card %s for %s / %s" % (card.itemID, card.lastSalePrice, card.price))
                        else:
                            logging.info("Removed sold card %s" % card.itemID)
        logging.info("All contracts relisted/removed")

    def getCoins(self):
        ''' Get information regarding available coins '''
        requestor = UrlRequestor("https://utas.s2.fut.ea.com/ut/game/fifa13/user/credits")
        requestor.addHeader({'Content-Type': 'application/json'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";" + self.EASF_SESS + "; " + self.FUTPHISHING + "; "})
        requestor.addHeader({'X-UT-SID': self.XUT_SID})
        requestor.addHeader({'x-http-method-override': 'GET'})
        requestor.open()
        if not requestor.status:
            logging.error("Error while trying to get coin information")
            return False
        return requestor.getReturnData().get('credits')

    def getUnAssignedIDs(self):
        watchListId = list()
        requestor = UrlRequestor("https://utas.s2.fut.ea.com/ut/game/fifa13/purchased/items")
        requestor.addHeader({'Content-Type': 'application/json'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";" + self.EASF_SESS + "; " + self.FUTPHISHING + "; "})
        requestor.addHeader({'X-UT-SID': self.XUT_SID})
        requestor.addHeader({'x-http-method-override': 'GET'})
        requestor.open()
        if not requestor.status:
            logging.error("Error while trying to get unassigned ids")
            return watchListId
        returnData = requestor.getReturnData().get('itemData')
        if requestor.status and isinstance(returnData, list):
            for card in returnData:
                watchListId.append(card.get('id'))
        return watchListId

    def quickSell(self, itemID):
        requestor = UrlRequestor('https://utas.s2.fut.ea.com/ut/game/fifa13/item/' + str(itemID))
        requestor.addHeader({'Content-Type': 'application/json'})
        requestor.addHeader({'Cookie': self.EASW_KEY + ";" + self.EASF_SESS + "; " + self.FUTPHISHING + "; "})
        requestor.addHeader({'x-http-method-override': 'DELETE'})
        requestor.addHeader({'X-UT-Embed-Error': True})
        requestor.open()

if __name__ == "__main__":
    import programs
    programs.autoContracts()
